/*
 * Copyright (c) 2018 Hitevision
 */

package tw.com.hitevision.whiteboard.android.widgets;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.net.Uri;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import androidx.core.content.FileProvider;
import androidx.viewpager.widget.ViewPager;
import tw.com.hitevision.whiteboard.android.Props;
import tw.com.hitevision.whiteboard.android.R;
import tw.com.hitevision.whiteboard.android.navigator.Item;
import tw.com.hitevision.whiteboard.android.navigator.PreviewPagerAdapter;
import tw.com.hitevision.whiteboard.android.state.WhiteboardState;
import tw.com.hitevision.whiteboard.android.storage.FileHandler;
import tw.com.hitevision.whiteboard.android.storage.FileHelper;
import tw.com.hitevision.whiteboard.android.storage.StorageHelper;
import tw.com.hitevision.whiteboard.android.storage.Volume;
import tw.com.hitevision.whiteboard.android.util.FileShareUtils;
import tw.com.hitevision.whiteboard.android.util.GlideApp;
import tw.com.hitevision.whiteboard.android.util.SystemPropertiesUtils;

import static tw.com.hitevision.whiteboard.android.util.SystemPropertiesUtils.KEY_SYSTEM_PLATFORM;

public class NavigatorView extends FrameLayout implements TenCentCloud.TenCentCloudCallBack {
    private static final String TAG = NavigatorView.class.getSimpleName();

    private static final int MAX_USB_NUM = 5;
    private static final int LOAD_FRAME_DURATION = 200;
    private static final long UPDATE_ANNOTATION_FILES_DELAY = 150; // ms

    private int maxNumWhiteboardStates;

    private ViewPager viewPager;
    private View delete;
    private View selectAll;
    private View share;
    private View copy;
    private View progress;
    private ImageView usb1Icon;
    private ImageView usb2Icon;
    private ImageView usb3Icon;
    private ImageView usb4Icon;
    private ImageView usb5Icon;
    private TextView usb1Label;
    private TextView usb2Label;
    private TextView usb3Label;
    private TextView usb4Label;
    private TextView usb5Label;

    private ImageView[] usbIcons;
    private TextView[] usbLabels;

    private PreviewPagerAdapter whiteboardAdapter;
    private PreviewPagerAdapter annotationAdapter;
    private PreviewPagerAdapter adapter;

    private Listener listener;

    private MediaBroadcastReceiver receiver;

    private FileHandler fileHandler;
    private List<Volume> volumes;

    private boolean isAnnotationMode;

    private View qrCode;
    private TenCentCloud tenCentCloud;

    public NavigatorView(Context context) {
        super(context);
        init(context);
    }

    public NavigatorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public NavigatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        inflate(context, R.layout.navigator, this);

        maxNumWhiteboardStates = context.getResources().getInteger(R.integer.max_number_of_whiteboard_states);

        final View container = findViewById(R.id.container);
        container.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });

        final View close = findViewById(R.id.close);
        close.setOnClickListener(v -> hide());

        selectAll = findViewById(R.id.select_all);
        selectAll.setOnClickListener(v -> {
            if (adapter.isEmpty()) {
                selectAll.setSelected(false);
            } else {
                selectAll.setSelected(!selectAll.isSelected());
            }

            if (selectAll.isSelected()) {
                adapter.selectAll();
                delete.setEnabled(true);

                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//                    share.setEnabled(true);
//                    if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                        qrCode.setEnabled(true);
//                    }
                    qrCode.setEnabled(true);

                    for (ImageView usb : usbIcons) {
                        usb.setEnabled(true);
                    }
                }

                if (Props.getPhase() >= Props.Phase.THREE) {
                    copy.setEnabled(adapter.getItemsSize() < maxNumWhiteboardStates);
                }
            } else {
                clearSelected();
            }
        });

        delete = findViewById(R.id.delete);
        delete.setOnClickListener(v -> {
            final int currentPage = viewPager.getCurrentItem();

            final List<Long> deleted = adapter.deleteSelected();
            if (listener != null) {
                listener.onStatesDeleted(deleted);
            }

            clearSelected();

            // add a delay before checking if current page doesn't exist anymore
            // the delay is needed because the view may not be up-to-date yet
            viewPager.postDelayed(() -> {
                if (currentPage >= adapter.getCount()) {
                    viewPager.setCurrentItem(adapter.getCount() - 1, true);
                }
            }, 80);
        });
        delete.setEnabled(false);

        copy = findViewById(R.id.copy);
        if (Props.getPhase() >= Props.Phase.THREE) {
            copy.setOnClickListener(v -> {
                if (listener != null) {
                    listener.onCopyStates(adapter.getSelectedIds());
                }

                clearSelected();
            });
            copy.setEnabled(false);
        } else {
            copy.setVisibility(View.GONE);
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            View closeLabel = findViewById(R.id.close_label);
            closeLabel.setSelected(true);

//            share = findViewById(R.id.navigator_share);
//            share.setOnClickListener(v -> {
//                doShare(context);
//            });
//            share.setEnabled(false);

            progress = findViewById(R.id.progress);
            progress.setVisibility(View.GONE);

            usb1Label = findViewById(R.id.usb1_label);
            usb2Label = findViewById(R.id.usb2_label);
            usb3Label = findViewById(R.id.usb3_label);
            usb4Label = findViewById(R.id.usb4_label);
            usb5Label = findViewById(R.id.usb5_label);

            usbLabels = new TextView[MAX_USB_NUM];
            usbLabels[0] = usb1Label;
            usbLabels[1] = usb2Label;
            usbLabels[2] = usb3Label;
            usbLabels[3] = usb4Label;
            usbLabels[4] = usb5Label;

            usb1Icon = findViewById(R.id.usb1_icon);
            usb2Icon = findViewById(R.id.usb2_icon);
            usb3Icon = findViewById(R.id.usb3_icon);
            usb4Icon = findViewById(R.id.usb4_icon);
            usb5Icon = findViewById(R.id.usb5_icon);

            usbIcons = new ImageView[MAX_USB_NUM];
            usbIcons[0] = usb1Icon;
            usbIcons[1] = usb2Icon;
            usbIcons[2] = usb3Icon;
            usbIcons[3] = usb4Icon;
            usbIcons[4] = usb5Icon;

            usb1Icon.setOnClickListener(usbOnClickListener);
            usb2Icon.setOnClickListener(usbOnClickListener);
            usb3Icon.setOnClickListener(usbOnClickListener);
            usb4Icon.setOnClickListener(usbOnClickListener);
            usb5Icon.setOnClickListener(usbOnClickListener);

            for (ImageView usb : usbIcons) {
                usb.setEnabled(false);
            }
            log("Platform : " + SystemPropertiesUtils.getStringValue(KEY_SYSTEM_PLATFORM, null));
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) &&
                    SystemPropertiesUtils.getStringValue(KEY_SYSTEM_PLATFORM, null).equals("RS_ZHEN")) {
                qrCode = findViewById(R.id.qr_code);
                qrCode.setOnClickListener(v -> {
                    final List<Item> items = adapter.getSelected();

                    if (items.isEmpty()) {
                        return;
                    }

                    final FileHelper fileHelper = FileHelper.getInstance(context);
                    if (tenCentCloud != null) {
                        Long number = System.currentTimeMillis() + getRandonInt(0, Integer.MAX_VALUE);
                        String fileFolder = number.toString();

                        log("Folder : " + fileFolder);

                        for (int i = 0; i < items.size(); i++) {
                            Item item = items.get(i);
                            final File file = fileHelper.getPreviewFile(item.getPreviewFile());
                            tenCentCloud.upload((i + 1) + ".jpg", file.getPath(), fileFolder, i == items.size() - 1, items.size());
                        }
                    }

                    clearSelected();
                    progress.setVisibility(View.GONE);
                });
                qrCode.setEnabled(false);

                tenCentCloud = TenCentCloud.getInstance(context);

                tenCentCloud.setListener(this);
            } else {
                qrCode = findViewById(R.id.qr_code);
                qrCode.setEnabled(false);
                if (qrCode != null) {
                    qrCode.setVisibility(VISIBLE);
                    qrCode.setOnClickListener(view -> {
                        listener.onExportClicked(adapter.getSelected());
//                        NavigatorViewQRCodeExportDialog navigatorViewQRCodeExportDialog = new NavigatorViewQRCodeExportDialog(context, adapter.getSelected());
//                        navigatorViewQRCodeExportDialog.show();
                    });
                }
                View qrCodeTitle = findViewById(R.id.qr_code_label);
                if (qrCodeTitle != null) {
                    qrCodeTitle.setVisibility(VISIBLE);
                }
            }
        }

        whiteboardAdapter = new PreviewPagerAdapter(context);
        whiteboardAdapter.setListener(adapterListener);

        annotationAdapter = new PreviewPagerAdapter(context);
        annotationAdapter.setListener(adapterListener);

        adapter = whiteboardAdapter;

        viewPager = findViewById(R.id.thumbnails);
        viewPager.setAdapter(adapter);

        setOnTouchListener(rootOnTouchListener);

        receiver = new MediaBroadcastReceiver();
    }

    public void clearSelected() {
        adapter.clearSelected();

        selectAll.setSelected(false);
        delete.setEnabled(false);
        qrCode.setEnabled(false);

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//            share.setEnabled(false);
            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
                qrCode.setEnabled(false);
            }

            for (ImageView usb : usbIcons) {
                usb.setEnabled(false);
            }
        }

        if (Props.getPhase() >= Props.Phase.THREE) {
            copy.setEnabled(false);
        }
    }

    public void setFileHandler(FileHandler fileHandler) {
        this.fileHandler = fileHandler;
    }

    private final View.OnClickListener usbOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            int index = -1;
            switch (v.getId()) {
                case R.id.usb1_icon: {
                    index = 0;
                    break;
                }
                case R.id.usb2_icon: {
                    index = 1;
                    break;
                }
                case R.id.usb3_icon: {
                    index = 2;
                    break;
                }
                case R.id.usb4_icon: {
                    index = 3;
                    break;
                }
                case R.id.usb5_icon: {
                    index = 4;
                    break;
                }
            }

            final List<Item> items = adapter.getSelected();
            if (index != -1 && volumes.size() > index && !items.isEmpty()) {
                final Volume volume = volumes.get(index);

                if (fileHandler != null) {
                    final String path = volume.getPath();
                    for (Item item : items) {
                        fileHandler.sendCopyPreviewMessage(item.getPreviewFile(), path, null);
                    }
                }

                final int frameDuration = LOAD_FRAME_DURATION * items.size();
                final AnimationDrawable loadDrawable = createUsbLoadingAnimation(frameDuration);

                final ImageView icon = usbIcons[index];
                icon.setImageDrawable(loadDrawable);
                loadDrawable.start();
                icon.postDelayed(() -> icon.setImageResource(R.drawable.ic_usb), 19 * frameDuration);

                clearSelected();
            }
        }
    };

    private AnimationDrawable createUsbLoadingAnimation(int frameDuration) {
        final Context res = getContext();

        final AnimationDrawable anim = new AnimationDrawable();
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_1), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_2), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_3), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_4), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_5), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_6), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_7), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_8), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_9), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_10), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_11), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_12), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_13), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_14), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_15), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_16), frameDuration);
        anim.addFrame(res.getDrawable(R.drawable.ic_usb_active_1), frameDuration);

        return anim;
    }

    private final PreviewPagerAdapter.Listener adapterListener = new PreviewPagerAdapter.Listener() {
        @Override
        public void onStateClick(long stateId) {
            if (listener != null) {
                listener.onStateClick(stateId);
            }
        }

        @Override
        public void onSelectedItemsChanged(int selectedCount, int itemsSize) {
            final boolean hasSelected = selectedCount > 0;
            delete.setEnabled(hasSelected);

            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//                share.setEnabled(hasSelected);
//                if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                    qrCode.setEnabled(hasSelected);
//                }
                qrCode.setEnabled(hasSelected);

                for (ImageView icon : usbIcons) {
                    icon.setEnabled(hasSelected);
                }
            }

            if (Props.getPhase() >= Props.Phase.THREE) {
                if (itemsSize < maxNumWhiteboardStates) {
                    copy.setEnabled(hasSelected);
                } else {
                    copy.setEnabled(false);
                }
            }

            selectAll.setSelected(selectedCount == itemsSize);
        }
    };

    public void setStates(List<WhiteboardState> states) {
        whiteboardAdapter.setStates(states, -1);
    }

    public void setStates(List<WhiteboardState> states, int currentIndex) {
        whiteboardAdapter.setStates(states, currentIndex);
    }

    public void setAnnotationMode(boolean enabled) {
        isAnnotationMode = enabled;

        if (enabled) {
            adapter = annotationAdapter;

            if (delete != null) {
                delete.setVisibility(View.GONE);
            }
            if (Props.getPhase() >= Props.Phase.THREE) {
                if (copy != null) {
                    copy.setVisibility(View.GONE);
                }
            }
        } else {
            adapter = whiteboardAdapter;

            if (delete != null) {
                delete.setVisibility(View.VISIBLE);
            }
            if (Props.getPhase() >= Props.Phase.THREE) {
                if (copy != null) {
                    copy.setVisibility(View.VISIBLE);
                }
            }
        }

        viewPager.setAdapter(adapter);
    }

    public boolean isAnnotationMode() {
        return isAnnotationMode;
    }

    public void setStatesDelayed(List<WhiteboardState> states, int currentIndex, long delayInMillis) {
        if (progress != null) {
            progress.setVisibility(View.VISIBLE);
        }

        postDelayed(() -> {
            if (progress != null) {
                progress.setVisibility(View.GONE);
            }
            whiteboardAdapter.setStates(states, currentIndex);
        }, delayInMillis);
    }

    public boolean isVisible() {
        return getVisibility() == View.VISIBLE;
    }

    public void show() {
        setVisibility(View.VISIBLE);

        if (isAnnotationMode) {
            postDelayed(() -> updateAnnotationAdapter(), UPDATE_ANNOTATION_FILES_DELAY);
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
            updateUsbStatus();

            // start text scrolling
            for (TextView label : usbLabels) {
                label.setSelected(true);
            }
        }
    }

    public void hide() {
        adapter.clear();
        setVisibility(View.INVISIBLE);
        invalidate();

        selectAll.setSelected(false);
        delete.setEnabled(false);

        if (progress != null) {
            progress.setVisibility(View.GONE);
        }

        if (Props.getPhase() >= Props.Phase.THREE) {
            copy.setEnabled(false);
        }

        if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs) || Props.getFlavorModel().equals(Props.Flavor.Model.Oem)) {
//            share.setEnabled(false);
//            if (Props.getFlavorModel().equals(Props.Flavor.Model.Rs)) {
//                qrCode.setEnabled(false);
//            }
            qrCode.setEnabled(false);

            // stop text scrolling
            for (TextView label : usbLabels) {
                label.setSelected(false);
            }

            for (ImageView usb : usbIcons) {
                usb.setEnabled(false);
            }
        }

        GlideApp.get(getContext().getApplicationContext()).clearMemory();
        System.gc();
    }

    public BroadcastReceiver getBroadcastReceiver() {
        return receiver;
    }

    private void updateUsbStatus() {
        log("updateUsbStatus");
        volumes = StorageHelper.getInstance(getContext()).getVolumes();
        final int volumesSize = volumes.size();

        for (int i = 0; i < MAX_USB_NUM; i++) {
            final TextView label = usbLabels[i];
            final ImageView icon = usbIcons[i];

            if (i < volumesSize) {
                label.setVisibility(View.VISIBLE);
                icon.setVisibility(View.VISIBLE);

                final Volume volume = volumes.get(i);
                label.setText(volume.getLabel());
                icon.setImageResource(R.drawable.ic_usb);
            } else {
                if (i == 0) {
                    label.setText(null);
                    icon.setImageResource(R.drawable.ic_usb_missing);
                    icon.setEnabled(false);
                } else {
                    label.setVisibility(View.GONE);
                    icon.setVisibility(View.GONE);
                }
            }
        }
    }

    private void doShare(Context context){

        progress.setVisibility(View.VISIBLE);

        final List<Item> items = adapter.getSelected();

        if (items.isEmpty()) {
            return;
        }

        final FileHelper fileHelper = FileHelper.getInstance(context);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            final ArrayList<String> files = new ArrayList<>(items.size());
            for (Item item : items) {
                final File file = fileHelper.getPreviewFile(item.getPreviewFile());
                files.add(file.toString());
            }

            Intent intent = FileShareUtils.createShareIntent(context, files);
            if (intent != null) {
                listener.onShareClicked(intent);
            } else {
                Log.e(TAG, "Sharer app not installed!");
            }
        } else {
            final String fileProvider = context.getString(R.string.file_provider);
            final ArrayList<Uri> uris = new ArrayList<>(items.size());
            for (Item item : items) {
                final File file = fileHelper.getPreviewFile(item.getPreviewFile());
                uris.add(FileProvider.getUriForFile(context, fileProvider, file));
            }

            final Intent intent = new Intent();
            intent.setAction(Intent.ACTION_SEND_MULTIPLE);
            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
            intent.setType("image/png");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_title)));
        }

//                selectAll.setSelected(false);
//                adapter.clearSelected();
        clearSelected();
        progress.setVisibility(View.GONE);

    }

    @SuppressLint("ClickableViewAccessibility")
    private final OnTouchListener rootOnTouchListener = (v, event) -> {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            hide();
        }
        return true;
    };

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    private Comparator<File> mostRecentComparator = new Comparator<File>() {
        @Override
        public int compare(File file1, File file2) {
            final long time1 = file1.lastModified();
            final long time2 = file2.lastModified();

            if (time1 > time2) {
                return -1;
            } else if (time1 == time2) {
                return file2.getName().compareTo(file1.getName());
            } else {
                return 1;
            }
        }
    };

    private void updateAnnotationAdapter() {
        final List<File> files = FileHelper.getInstance(getContext()).getAnnotationScreenshots();
        Collections.sort(files, mostRecentComparator);
        annotationAdapter.setFiles(files);
    }

    public interface Listener {
        void onStateClick(long stateId);

        void onStatesDeleted(List<Long> deleted);

        void onCopyStates(List<Long> ids);

        void showQRCode(String url);

        void onShareClicked(Intent intent);

        void onExportClicked(List<Item> selected);
    }

    private class MediaBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            log("MediaBraodcastReceiver.onReceive: intent=" + intent);
            updateUsbStatus();
        }
    }

    @Override
    public void onFinish(String url) {
        if (listener != null) {
            listener.showQRCode(url);
        }
    }

    private int getRandonInt(int min, int max) {
        return min + (int) (Math.random() * ((max - min) + 1));
    }

    private static void log(String msg) {
        Log.d(TAG, msg);
    }
}
